#include "../StdAfx.h"
#include "Connection.h"

Connection::Connection(boost::asio::io_service& ioService) :
		mStrand(ioService), mSocket(ioService), isClosing(false)
{

}

Connection::~Connection()
{

}

boost::asio::ip::tcp::socket& Connection::getSocket()
{

	return mSocket;

}

boost::asio::ip::tcp::endpoint Connection::getEndPoint()
{

	return mEndPoint;

}

void Connection::start()
{

	mEndPoint = mSocket.remote_endpoint();

	Log->info("Se ha establecido conexion:%s:%d",mSocket.remote_endpoint().address().to_string().c_str(),mSocket.remote_endpoint().port());

	boost::asio::socket_base::keep_alive _keepAlive(true);
	mSocket.set_option(_keepAlive);

	boost::asio::async_read(mSocket,boost::asio::buffer(mBuffer,1),
		mStrand.wrap( boost::bind(&Connection::handleRead,shared_from_this(),
		boost::asio::placeholders::error,
		boost::asio::placeholders::bytes_transferred)) );

}

void Connection::close()
{
	close(false);
}

void Connection::close(bool remove)
{

	boost::system::error_code _eShutdown, _eClose;

	mMuxCon.lock();
	if ( !isClosing )
		isClosing = true;
	else
	{
		mMuxCon.unlock();
		return;
	}
	mMuxCon.unlock();

	mSocket.shutdown(boost::asio::ip::tcp::socket::shutdown_both, _eShutdown);

	if ( _eShutdown )
		Log->error("Socket shutdown error %d : %s",_eShutdown.value(),_eShutdown.message().c_str());

	mSocket.close(_eClose);

	if ( _eClose )
		Log->error("Socket close error %d : %s",_eClose.value(),_eClose.message().c_str());


	if ( remove )
		Net->removeConnection(shared_from_this());
}

void Connection::handleRead(const boost::system::error_code& e,
		std::size_t bytesTransferred)
{

	if ( !e )
	{

		mBuffer[bytesTransferred] = '\0';
		Log->info("Leidos %i bytes, msg=%s",bytesTransferred,mBuffer);
		boost::asio::async_write(mSocket,boost::asio::buffer(mBuffer,1),
			 mStrand.wrap( boost::bind(&Connection::handleWrite,shared_from_this(),
			boost::asio::placeholders::error)) );

	}
	else
		handleError(e);

}

void Connection::handleError(const boost::system::error_code& e)
{

	switch(e.value())
	{

		case boost::asio::error::eof:
			Log->warning("[Connection]:Recibido EOF");
			//Connection::remove();
			break;

		case boost::asio::error::operation_aborted:
			Log->warning("[Connection]:Operacion de socket abortada");
			break;

		case boost::asio::error::connection_reset:
			Log->warning("[Connection]:Conexion reseteada por el cliente");
			//Connection::remove();
			break;

		default:
			Log->warning("[Connection]:Error de socket no esperado %d",e.value());
			//Connection::remove();
			break;

	}

	Connection::close(true);

}

void Connection::handleWrite(const boost::system::error_code& e)
{

	if ( !e )
	{

		boost::asio::async_read(mSocket,boost::asio::buffer(mBuffer,1),
			mStrand.wrap( boost::bind(&Connection::handleRead,shared_from_this(),
			boost::asio::placeholders::error,
			boost::asio::placeholders::bytes_transferred)) );

	}
	else
		handleError(e);

}
